package com.arofoxmsn.repository;

import java.util.Arrays;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;

import com.arofoxmsn.utils.FlashMessage;
import com.arofoxmsn.utils.FlashMessage.Type;

/**
 * this class is in charge of making crud basic operations
 * it will be extended by all repository classes in order
 * to take advantage of all crud methods
 * @author arodm
 * @param <T> The Model class implemented by the repository class  
 */
public abstract class BaseTable<T> {
	
	
	private enum OperationType{UPDATE,DELETE};
	
	/*
	 * this method is in charge of wrap an action to be executed
	 * in a session environment, is a factory of actions.
	 */
	private FlashMessage factoryAction(OperationType operation, T...args){
		SessionFactory factory = MyHibernateConfig.getHibernateFactory();
		Session session = factory.openSession();
		session.beginTransaction();
		FlashMessage flash = new FlashMessage(Type.OK, "");
		switch(operation){
			case UPDATE:
				for(T anObject : args){
					String message = new String();
					try{
						session.saveOrUpdate(anObject);
						flash.setDescription("All records where saved!");
					}catch(Exception e){
						e.printStackTrace();
						message += anObject.toString()+"\n";
						flash = new FlashMessage(Type.ERROR, "Error in: " +message);
					}
				}
				break;
			case DELETE:
				break;
		}
		session.getTransaction().commit();
		session.close();
		return flash;
	}
	/**
	 * <b>Abstract</b>
	 * this class is in charge of retrieving which model class is
	 * trying to retrieving to
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	protected abstract Class getModelClass();
	
	/**
	 * this method is in charge of saving one object, it is public
	 * in order to saving all public repositories 
	 * @param args
	 * @return
	 */
	public FlashMessage save(T...args){
		return factoryAction(OperationType.UPDATE,args);
	}
	
	/**
	 * it retrieves all Objects those accomplish with given
	 * Criteria
	 * @param criterios
	 * @return
	 */
	public List<T> retrieveAll(Criterion... criterios){
		SessionFactory factory = MyHibernateConfig.getHibernateFactory();
		Session session = factory.openSession();
		Criteria criteria = session.createCriteria(getModelClass());
		for(Criterion oneCriterio : criterios){
			criteria.add(oneCriterio);
		}
		@SuppressWarnings("unchecked")
		List<T> listToReturn = (List<T>) criteria.list();
//		session.getTransaction().commit();
//		session.close();
		return listToReturn;
	}
	/**
	 * it retrieves one object
	 * @param  the object id
	 * @return
	 */
	public T retrieveById(int id){
		return retrieveAll(Restrictions.eq("id", id)).get(0);
	}
	/**
	 * overloaded method
	 * @param id long
	 * @return
	 */
	public T retrieveById(long id){
		return retrieveAll(Restrictions.eq("id", id)).get(0);
	}
	
	/**
	 * it retrieves a collection of objects those ids where passed
	 * by parameter
	 * @param ids the objects ids
	 * @return
	 */
	public List<T> retrieveByMultiplesId(int ...ids){
		return retrieveAll(Restrictions.in("id", Arrays.asList(ids)));
	}
	
}
